package com.fishery.quartz.util;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.ClassUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;


public class MyBeanUtil extends BeanUtils {

	public static void copyProperties(Object source, Object target, boolean isAllowableNull) {
		copyProperties(source, target, isAllowableNull, null);
	}

	public static void copyProperties(Object source, Object target, boolean isAllowableNull, String... ignoreProperties) {
		if (source == null) {
			throw new NullPointerException("Source must not be null");
		}
		if (target == null) {
			throw new NullPointerException("Target must not be null");
		}
		Class<?> editTarget = target.getClass();
		PropertyDescriptor[] targetPds = getPropertyDescriptors(editTarget);
		List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
		for (PropertyDescriptor targetPd : targetPds) {
			Method writeMethod = targetPd.getWriteMethod();
			if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
				PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
				if (sourcePd != null) {
					Method readMethod = sourcePd.getReadMethod();
					if (readMethod != null &&
							ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
						try {
							if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
								readMethod.setAccessible(true);
							}
							Object value = readMethod.invoke(source);
							if (!isAllowableNull && value == null) {
								continue;
							}
							if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
								writeMethod.setAccessible(true);
							}
							writeMethod.invoke(target, value);
						} catch (Throwable ex) {
							throw new FatalBeanException(
									"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
						}
					}
				}
			}
		}
	}

}
